[小ネタ] S3 SelectでCSVの列名に特殊文字が入っている場合

[小ネタ] S3 SelectでCSVの列名に特殊文字が入っている場合

S3 Selectで、CSVの列名にスラッシュなどの特殊文字が入っている場合のクエリの書き方で若干ハマったので記事にしてみました。
Clock Icon2019.04.09

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

問題

S3 Selectで、以下のようにCSVの列名に特殊な文字が入っている場合の話です。

aaa/aaa,bbb?bbb,ccc;ccc
aaa1,bbb1,ccc1
aaa2,bbb2,ccc2

ここで例えばaaa/aaa列だけを取り出したいとき、どうすれば良いでしょうか?

とりあえずやってみる

Python (boto3)でやってみます。まず、以下のようなコードを書いてみます。FileHeaderInfo: USEとしてヘッダ行を使用する設定にしています。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import boto3
client = boto3.client('s3', 'ap-northeast-1')

bucket_name = 'test-bucket-name'
key = 'test.csv'

response = client.select_object_content(
    Bucket = bucket_name,
    Key = key,
    ExpressionType = 'SQL',
    Expression = 'SELECT s.aaa/aaa FROM S3Object s',
    InputSerialization = {
        'CompressionType': 'NONE',
        'CSV': {
            'FileHeaderInfo': 'USE',
            'RecordDelimiter': '\n',
            'FieldDelimiter': ','
        }
    },
    OutputSerialization = {
        'CSV': {
            'RecordDelimiter': '\n',
            'FieldDelimiter': ','
        }
    }
)

for event in response[ 'Payload' ]:
    if 'Records' in event:
        records = event[ 'Records' ][ 'Payload' ].decode( 'utf-8' )
        print(records)

これを実行すると、以下のようなエラーになります。

botocore.exceptions.ClientError: An error occurred (MissingHeaders) when calling the SelectObjectContent operation: Some headers in the query are missing from the file. Please check the file and try again.

では、どうすれば良いのでしょうか?

解決

前置きが長すぎましたが、列名aaa/aaaをダブルクォートでくくれば解決します。分かっていれば簡単ですね。

    Expression = 'SELECT s."aaa/aaa" FROM S3Object s',

実行すると以下のように正しく結果が得られます。

aaa1
aaa2

なお、S3 Selectにおいては、以下のようにダブルクォートには特別な意味があります。

補足:スラッシュを含むCSV

そもそも列名にそんな変な文字入れなきゃいいじゃん、という話なのですが、実は列名にスラッシュが含まれているCSVが存在します。 それがAWSのコストと使用状況レポート(AWS Cost & Usage Report, 以下CUR)です。

CURのヘッダ行にはlineItem/ProductCode, lineItem/UsageTypeのようにスラッシュが含まれています。 ですので、これをS3 Selectで扱う場合はダブルクォートが必要です。例えばCURからS3関係の行だけを取り出したければ以下のようになります。

SELECT * FROM S3Object s WHERE s."lineItem/ProductCode" = 'AmazonS3'

業務上でCURを扱う機会があり、S3 Selectを使ってみたらちょっとハマったのでメモとして残してみました。レアケースだとは思いますが、どこかで誰かのお役に立てば幸いです。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.